﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

using RedLockNet;
using RedLockNet.SERedis;
using RedLockNet.SERedis.Configuration;

using StackExchange.Redis;

namespace Jack.RedisLib
{
    public class RedisLock : IRedisLock, IDisposable
    {
        private readonly RedLockFactory _redLockFactory;
        private readonly RedisOptions _options;
        private readonly ConnectionMultiplexer _connectionMultiplexer;
        private readonly ILoggerFactory _loggerFactory;

        public RedisLock(IOptions<RedisOptions> options, ILoggerFactory loggerFactory)
        {
            _options = options.Value;
            _loggerFactory = loggerFactory;

            _connectionMultiplexer = ConnectionMultiplexer.Connect(_options.ConnectionString, _options.Debug ? Console.Out : null);

            List<RedLockMultiplexer> redLockMultiplexers = [_connectionMultiplexer];
            _redLockFactory = RedLockFactory.Create(redLockMultiplexers, _options.Debug ? _loggerFactory : null);
        }

        /// <summary>
        /// 创建红锁
        /// </summary>
        /// <param name="resource">锁定的资源标识</param>
        /// <param name="expireTime">锁的过期时间（防止锁未释放，导致死锁）</param>
        /// <returns>红锁</returns>
        public async Task<IRedLock> CreateLockAsync(string resource, TimeSpan expireTime)
        {
            if (!string.IsNullOrWhiteSpace(_options.InstanceName))
            {
                resource = $"{_options.InstanceName}{resource}";
            }

            return await _redLockFactory.CreateLockAsync(resource, expireTime);
        }

        /// <summary>
        /// 创建红锁
        /// </summary>
        /// <param name="resource">锁定的资源标识</param>
        /// <param name="expireTime">锁的过期时间（防止锁未释放，导致死锁）</param>
        /// <param name="waitTime">等待获取锁的最长时间，超时会直接返回</param>
        /// <param name="retryTime">重试获取锁的时间间隔</param>
        /// <param name="cancellationToken">取消等待的令牌</param>
        /// <returns>红锁</returns>
        public async Task<IRedLock> CreateLockAsync(string resource, TimeSpan expireTime, TimeSpan waitTime, TimeSpan retryTime, CancellationToken cancellationToken = default)
        {
            if (!string.IsNullOrWhiteSpace(_options.InstanceName))
            {
                resource = $"{_options.InstanceName}{resource}";
            }

            return await _redLockFactory.CreateLockAsync(resource, expireTime, waitTime, retryTime, cancellationToken);
        }

        public void Dispose()
        {
            _connectionMultiplexer?.Dispose();
            _redLockFactory?.Dispose();
        }
    }
}
